import axios from 'axios'

import { ACCESS_TOKEN } from '@/stores/mutation-types'
import { notification } from 'ant-design-vue'
import { useUserStore } from '@/stores/user'
import JSONBig from 'json-bigint'

const request = axios.create({ // 创建axios实例，用于发送请求
    baseURL: import.meta.env.BASE_URL || 'http://localhost:8080', // 基础URL，用于拼接请求URL
    timeout: 5000, // 请求超时时间，单位为毫秒，超过该时间请求将被中断
    headers: { // 请求头，用于设置请求头信息，如token、content-type等
        'Content-Type': 'application/json', // 设置请求头为json格式，用于发送json数据
    },
    transformResponse: [function (data) {
        /**
       * 响应数据处理，用于对响应数据进行预处理，如格式化、解密等
       */
      try {
          return JSONBig.parse(data)
      } catch (error) {
          return {
            data
          }
      }
    }],
})


const codeMessage = { // 定义错误码对应的错误信息
    200: '服务器成功返回请求的数据。',
    201: '新建或修改数据成功。',
    202: '一个请求已经进入后台排队（异步任务）。',
    204: '删除数据成功。',
    400: '发出的请求有错误，服务器没有进行新建或修改数据的操作。',
    401: '用户没有权限（令牌、用户名、密码错误）。',
    403: '用户得到授权，但是访问是被禁止的。',
    404: '发出的请求针对的是不存在的记录，服务器没有进行操作。',
    406: '请求的格式不可得。',
    410: '请求的资源被永久删除，且不会再得到的。',
    422: '当创建一个对象时，发生一个验证错误。',
    500: '服务器发生错误，请检查服务器。',
    502: '网关错误。',
    503: '服务不可用，服务器暂时过载或维护。',
    504: '网关超时。',
}
/**
 * 异常处理程序
 */
const errorHandler = (error: any) => { // error是错误对象，包含了错误信息，如状态码、错误信息等
    const { response } = error // 解构错误对象，获取响应对象
    if (response) { // 如果响应对象存在，则说明请求出错了，需要处理错误信息
        const statusCode = response.status as keyof typeof codeMessage;
        const errorText = codeMessage[statusCode] || response.statusText; // 获取错误信息，如状态码对应的错误信息，或状态码对应的错误信息

        const { status, url } = response // 解构响应对象，获取状态码、请求URL等信息
        console.error(`请求错误 ${status}: ${url}`) // 打印错误信息，如状态码、请求URL等信息
        console.error(errorText) // 打印错误信息，如错误信息

        if (status === 401) { // 如果状态码为401，则说明用户没有权限，需要跳转到登录页面
            console.warn('未登录或登录已过期，请重新登录。') // 打印警告信息，如未登录或登录已过期，请重新登录。
            notification.error({ // 弹出错误提示框，用于提示用户未登录或登录已过期
                message: '未登录', // 提示框标题
                description: codeMessage[401], // 提示框内容
                duration: 4, // 提示框显示时间，单位为秒
            })
            if (localStorage.getItem('token')) { // 如果localStorage中存在token，则说明用户已经登录过了，需要清除token
                useUserStore().logout().then(() => {
                  window.location.reload()
                  return
                } ) // 调用logout方法，用于清除token
            }
        }
        if (status === 403) { // 如果状态码为403，则说明用户没有权限，需要跳转到403页面
            console.warn('无权限访问，请联系管理员。') // 打印警告信息，如无权限访问，请联系管理员。
            notification.error({ // 弹出错误提示框，用于提示用户无权限访问
                message: '无权限访问', // 提示框标题
                description: codeMessage[403], // 提示框内容
                duration: 4, // 提示框显示时间，单位为秒
            })
          return;
        }
        if (status === 500 ) {
          notification.error({
            message: '服务器错误',
            description: codeMessage[500] || '服务器错误，请联系管理员。',
            duration: 4,
          })
          return;
        }
        if (status !== 404) {
          notification.error({
            message: '请求错误',
            description: codeMessage[404] || '请求错误，请联系管理员。',
            duration: 4,
          })
          return;
        }

    } else { // 如果响应对象不存在，则说明请求没有出错，需要处理网络错误信息
        console.error('请求出错，请稍后重试') // 打印错误信息，如请求出错，请稍后重试
    }
    return Promise.reject(error) // 返回一个拒绝的Promise对象，用于中断请求
}


// 添加请求拦截器，用于在请求发送前做一些处理，如添加token、设置请求头等
request.interceptors.request.use(
    config => { // config是请求的配置对象，包含了请求的url、method、headers、data等信息
        const token = localStorage.getItem('token') // 从localStorage中获取token
        if (token) { // 如果token存在，则将token添加到请求头中，用于认证
            config.headers[ACCESS_TOKEN] = token // 设置请求头中的Authorization字段，值为Bearer token
        }
        return config // 返回配置对象，用于发送请求
    },
    error => { // 如果请求出错，则会进入该函数，error是错误对象，包含了错误信息，如状态码、错误信息等
        return Promise.reject(error) // 返回一个拒绝的Promise对象，用于中断请求
    }
)


// 添加响应拦截器，用于在响应返回后做一些处理，如解析响应数据、处理错误等
request.interceptors.response.use(
    response => { // response是响应对象，包含了响应的状态码、响应头、响应数据等信息
        return response.data // 返回响应数据，用于后续处理
    },
    errorHandler
)


export default request // 导出axios实例，用于发送请求
